library(tidyverse)
library(ggthemes)
library(gridExtra)
library(langcog) # for multi_boot_standard
theme_set(theme_few())
# langcog package is installed by running
# install.packages("devtools")
# devtools::install_github("langcog/langcog")
# make a base plots
# for flipped coordinate system with prop correct on x
p1 <- ggplot() +
geom_hline(yintercept = 1/3, lty = 2) +
scale_y_continuous("Proportion Correct", limits = c(-0.05, 1.05)) +
theme(axis.title.y = element_blank(), axis.ticks.y = element_blank())
p2 <- p1 + theme(axis.text.y = element_blank())
Intro
These are some preliminary visualizations of the data.
phylo <- read_csv("../data/species_data.csv") %>%
select(species, species_formatted, clade, clade_formatted, phylo)
mp_data <- read.csv("../data/merged_data/01_manyprimates_pilot_merged_data_v2.csv",
stringsAsFactors = F) %>%
left_join(phylo, by = "species") %>%
mutate(species = species_formatted,
species = reorder(species, phylo),
clade = clade_formatted,
clade = fct_relevel(clade, "Lemur", "New World monkey", "Old World monkey", "Ape"),
delay = factor(delay))
Overview by species
First an overview of the data, plotted by species and delay. Small, transparent dots represent aggregated data for each individual by delay. Open dots are the group mean for that delay. Error bars are 95% confidence intervals. Text labels are the sample size.
plot_individual <- mp_data %>%
group_by(phylo, clade, species, delay, subject_site) %>%
summarise(correct = mean(correct),
nr_trials = max(trial))
plot_group <- plot_individual %>%
multi_boot_standard(col = "correct")
# get sample sizes (for use in plots)
ns <- mp_data %>%
group_by(clade, species) %>%
mutate(n = n_distinct(subject_site)) %>%
group_by(clade, species, site, n) %>%
summarise(n_by_site = n_distinct(subject_site))
p2 + aes(x = delay, y = correct, col = delay) +
geom_jitter(data = plot_individual, aes(size = nr_trials), width = .1, height = .015, alpha = .15) +
geom_point(data = plot_group, aes(y = mean), shape = 1, size = 3, stroke = 1.5) +
geom_linerange(data = plot_group, aes(y = NULL, ymin = ci_lower, ymax = ci_upper), lwd = 1.2) +
# geom_text(data = ns, aes(label = n), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(species ~ ., switch = "y") +
theme(strip.text.y = element_text(angle = 180, hjust = 0)) +
scale_size_area("Number of Trials", max_size = 3, breaks = c(12, 24, 36)) +
scale_colour_solarized("Delay", breaks = c("short", "medium", "long")) +
coord_flip(ylim = 0:1)

ggsave("../graphs/02_01_overview.png", width = 4, height = 4.5, scale = 2)
ggsave("../graphs/Fig2.tiff", width = 4, height = 4.5, scale = 2, type = "cairo", compression = "lzw")
Overview by species across delays
plot_individual2 <- plot_individual %>%
group_by(clade, species, subject_site) %>%
summarise(correct = mean(correct))
plot_group2 <- plot_individual2 %>%
multi_boot_standard(col = "correct")
p1 + aes(x = fct_rev(species), y = correct, col = clade) +
geom_jitter(data = plot_individual2, width = .1, height = .015, alpha = .15, size = 3) +
geom_point(data = plot_group2, aes(y = mean), shape = 1, size = 3, stroke = 1.5) +
geom_linerange(data = plot_group2, aes(y = NULL, ymin = ci_lower, ymax = ci_upper), lwd = 1.2) +
geom_text(data = ns, aes(label = n), y = -.05, col = "black", size = 3) +
facet_grid(clade ~ ., scales = "free_y", space = "free_y") +
theme(strip.text.y = element_blank()) +
scale_colour_solarized() +
coord_flip()

ggsave("../graphs/02_02_overview_across_delays.png", width = 4, height = 1.8, scale = 2)
Plots by site
Here we select the species for which we have data from multiple sites. This is a very preliminary way of checking whether there is a lot of variation between sites. Plotting conventions are the same as above.
First we check for which species we have data from more than one site:
mp_data %>%
group_by(species) %>%
summarise(sites = n_distinct(site)) %>%
arrange(desc(sites)) %>%
knitr::kable()
| Chimpanzee |
5 |
| Ring-tailed lemur |
2 |
| Brown capuchin monkey |
2 |
| Bonobo |
2 |
| Gorilla |
2 |
| Black-and-white ruffed lemur |
1 |
| Black-faced spider monkey |
1 |
| Squirrel monkey |
1 |
| Rhesus macaque |
1 |
| Long-tailed macaque |
1 |
| Barbary macaque |
1 |
| Orangutan |
1 |
Chimpanzees
chimp_plot_individual <- mp_data %>%
filter(species == "Chimpanzee") %>%
group_by(site, delay, subject_site) %>%
summarise(correct = mean(correct))
chimp_plot_group <- chimp_plot_individual %>%
multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
geom_jitter(data = chimp_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
geom_pointrange(data = chimp_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
geom_text(data = filter(ns, species == "Chimpanzee"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(site ~ ., switch = "y") +
theme(strip.text.y = element_text(angle = 180)) +
scale_colour_solarized(breaks = c("short", "medium", "long")) +
ggtitle("Chimpanzees") +
coord_flip()

# ggsave("../graphs/02_03_chimp_by_site.png", width = 4, height = 2.5, scale = 2, type = "cairo", compression = "lzw")
ggsave("../graphs/02_03_chimp_by_site.png", width = 4, height = 2.5, scale = 2)
Ring-tailed lemurs
rtlemur_plot_individual <- mp_data %>%
filter(species == "Ring-tailed lemur") %>%
group_by(site, delay, subject_site) %>%
summarise(correct = mean(correct))
rtlemur_plot_group <- rtlemur_plot_individual %>%
multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
geom_jitter(data = rtlemur_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
geom_pointrange(data = rtlemur_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
geom_text(data = filter(ns, species == "Ring-tailed lemur"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(site ~ ., switch = "y") +
theme(strip.text.y = element_text(angle = 180)) +
scale_colour_solarized(breaks = c("short", "medium", "long")) +
ggtitle("Ring-tailed lemurs") +
coord_flip()

ggsave("../graphs/02_04_rtlemur_by_site.png", width = 4, height = 1.2, scale = 2)
Brown Capuchins
cap_plot_individual <- mp_data %>%
filter(species == "Brown capuchin monkey") %>%
group_by(site, delay, subject_site) %>%
summarise(correct = mean(correct))
cap_plot_group <- cap_plot_individual %>%
multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
geom_jitter(data = cap_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
geom_pointrange(data = cap_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
geom_text(data = filter(ns, species == "Brown capuchin monkey"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(site ~ ., switch = "y") +
theme(strip.text.y = element_text(angle = 180)) +
scale_colour_solarized(breaks = c("short", "medium", "long")) +
ggtitle("Capuchin Monkeys") +
coord_flip()

ggsave("../graphs/02_05_capuchin_by_site.png", width = 4, height = 1.2, scale = 2)
Bonobos
bon_plot_individual <- mp_data %>%
filter(species == "Bonobo") %>%
group_by(site, delay, subject_site) %>%
summarise(correct = mean(correct))
bon_plot_group <- bon_plot_individual %>%
multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
geom_jitter(data = bon_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
geom_pointrange(data = bon_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
geom_text(data = filter(ns, species == "Bonobo"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(site ~ ., switch = "y") +
theme(strip.text.y = element_text(angle = 180)) +
scale_colour_solarized(breaks = c("short", "medium", "long")) +
ggtitle("Bonobos") +
coord_flip()

ggsave("../graphs/02_06_bonobo_by_site.png", width = 4, height = 1.2, scale = 2)
Gorilla
gor_plot_individual <- mp_data %>%
filter(species == "Gorilla") %>%
group_by(site, delay, subject_site) %>%
summarise(correct = mean(correct))
gor_plot_group <- gor_plot_individual %>%
multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
geom_jitter(data = gor_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
geom_pointrange(data = gor_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
geom_text(data = filter(ns, species == "Gorilla"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(site ~ ., switch = "y") +
theme(strip.text.y = element_text(angle = 180)) +
scale_colour_solarized(breaks = c("short", "medium", "long")) +
ggtitle("Gorillas") +
coord_flip()

ggsave("../graphs/02_07_gorilla_by_site.png", width = 4, height = 1.2, scale = 2)
Task-experience
Here we split each species by task experience. Check if we have species with sufficient memebers having different levels of task experience.
mp_data %>%
group_by(species) %>%
mutate(lvls_task_exp = n_distinct(task_experience)) %>%
filter(lvls_task_exp > 1) %>%
group_by(species, task_experience) %>%
summarise(n = n_distinct(subject_site)) %>%
knitr::kable()
| Chimpanzee |
no |
19 |
| Chimpanzee |
yes |
32 |
| Bonobo |
no |
6 |
| Bonobo |
yes |
5 |
# get sample sizes (for use in plots)
ns_task_exp <- mp_data %>%
group_by(clade, species) %>%
mutate(n = n_distinct(task_experience)) %>%
group_by(clade, species, task_experience, n) %>%
summarise(n_by_site = n_distinct(subject_site))
So far, this only applies to chimps and bonobos. However, task experience co-varies with site.
chimp_task_plot_individual <- mp_data %>%
filter(species == "Chimpanzee") %>%
group_by(site, task_experience, delay, subject_site) %>%
summarise(correct = mean(correct))
chimp_task_plot_group <- mp_data %>%
filter(species == "Chimpanzee") %>%
group_by(task_experience, delay, subject_site) %>%
summarise(correct = mean(correct)) %>%
multi_boot_standard(col = "correct")
p_taskexp_chimp <- p2 + aes(x = delay, y = correct) +
geom_jitter(data = chimp_task_plot_individual, aes(col = site), width = .3, height = .015, alpha = .5, size = 3) +
geom_pointrange(data = chimp_task_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper, shape = delay), size = .8, stroke = 1.5) +
geom_text(data = filter(ns_task_exp, species == "Chimpanzee"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(task_experience ~ ., switch = "y") +
theme(legend.box = "horizontal", strip.text.y = element_text(angle = 180)) +
scale_shape_manual(values = c(1, 2, 5), breaks = c("short", "medium", "long")) +
scale_colour_solarized() +
ggtitle("Chimpanzees") +
coord_flip()
bonobo_task_plot_individual <- mp_data %>%
filter(species == "Bonobo") %>%
group_by(site, task_experience, delay, subject_site) %>%
summarise(correct = mean(correct))
bonobo_task_plot_group <- mp_data %>%
filter(species == "Bonobo") %>%
group_by(task_experience, delay, subject_site) %>%
summarise(correct = mean(correct)) %>%
multi_boot_standard(col = "correct")
p_taskexp_bon <- p2 + aes(x = delay, y = correct) +
geom_jitter(data = bonobo_task_plot_individual, aes(col = site), width = .3, height = .015, alpha = .5, size = 3) +
geom_pointrange(data = bonobo_task_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper, shape = delay), size = .8, stroke = 1.5) +
geom_text(data = filter(ns_task_exp, species == "Bbonobo"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
facet_grid(task_experience ~ ., switch = "y") +
theme(legend.box = "horizontal", strip.text.y = element_text(angle = 180)) +
scale_shape_manual(values = c(1, 2, 5), breaks = c("short", "medium", "long")) +
scale_colour_solarized() +
ggtitle("Bonobos") +
coord_flip()
grid.arrange(p_taskexp_chimp, p_taskexp_bon, ncol = 1)

grob <- arrangeGrob(p_taskexp_chimp, p_taskexp_bon, ncol = 1)
ggsave("../graphs/02_08_task_experience.png", grob, width = 4, height = 3, scale = 2)
Age
Here we plot age against correct choice separate for each delay and species. Regression line is smoothed delayal mean.
plot_age <- mp_data %>%
mutate(delay = fct_rev(delay)) %>%
group_by(subject_site, norm_age, clade, species, delay) %>%
summarise(correct = mean(correct))
ggplot(plot_age, aes(x = norm_age, y = correct)) +
geom_jitter(aes(col = clade), width = .05, height = .05, alpha = .5, size = 2.5) +
geom_smooth(method = "lm", col = "black") +
# geom_vline(xintercept = 0, lty = 2) +
geom_hline(yintercept = 1/3, lty = 2) +
facet_grid(~ delay) +
labs(x = "Normed Age (relative to species longevity)", y = "Proportion Correct") +
scale_color_solarized("Clade") +
ylim(c(-.05, 1.05))

ggsave("../graphs/02_09_age_by_delay.png", width = 4, height = 1.3, scale = 2)
ggsave("../graphs/Fig4.tiff", width = 4, height = 1.3, scale = 2, type = "cairo", compression = "lzw")
ggplot(plot_age, aes(x = norm_age, y = correct)) +
geom_jitter(aes(fill = species), width = .05, height = .05, alpha = .5, size = 2.5, shape = 21, stroke = 0) +
geom_smooth(aes(col = delay), method = "lm", show.legend = F) +
geom_vline(xintercept = 0, lty = 2) +
geom_hline(yintercept = 1/3, lty = 2) +
facet_grid(delay ~ clade, scales = "free_x") +
labs(x = "Normed Age (relative to species longevity)", y = "Proportion Correct") +
theme(legend.position = "bottom") +
scale_color_manual(values = rev(solarized_palette(3))) +
ylim(c(-.05, 1.05))

ggsave("../graphs/02_10_age_by_delay_species.png", width = 4, height = 3.4, scale = 2)
Cup distance
(sig. effect in preliminary model)
plot_cup <- mp_data %>%
group_by(subject_site, cup_distance, clade, species, delay) %>%
summarise(correct = mean(correct))
cp <- ggplot(plot_cup, aes(x = cup_distance, y = correct)) +
geom_jitter(aes(col = clade), width = .5, height = .15, alpha = .5, size = 2) +
geom_smooth(method = "lm", col = "black") +
labs(x = "Cup Distance in cm", y = "Proportion Correct") +
geom_hline(yintercept = 1/3, lty = 2) +
scale_color_solarized("Clade") +
ylim(c(-.05, 1.05))
cp + theme(plot.margin = unit(c(.5, 5, .5, .5), "cm"))

ggsave("../graphs/02_11_cup_distance.png", cp, width = 3, height = 2, scale = 2)
LS0tCnRpdGxlOiAiTWFueVByaW1hdGVzIHBsb3RzIgphdXRob3I6ICJNYW51ZWwgQm9obiIKZGF0ZTogIk9jdCAzMSAyMDE4IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY3NzOiBzdHlsZS5jc3MKICAgIHRoZW1lOiBwYXBlcgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShsYW5nY29nKSAjIGZvciBtdWx0aV9ib290X3N0YW5kYXJkCiAgCnRoZW1lX3NldCh0aGVtZV9mZXcoKSkKCiMgbGFuZ2NvZyBwYWNrYWdlIGlzIGluc3RhbGxlZCBieSBydW5uaW5nCiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigibGFuZ2NvZy9sYW5nY29nIikKYGBgCgpgYGB7cn0KIyBtYWtlIGEgYmFzZSBwbG90cwojIGZvciBmbGlwcGVkIGNvb3JkaW5hdGUgc3lzdGVtIHdpdGggcHJvcCBjb3JyZWN0IG9uIHgKcDEgPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEvMywgbHR5ID0gMikgKwogIHNjYWxlX3lfY29udGludW91cygiUHJvcG9ydGlvbiBDb3JyZWN0IiwgbGltaXRzID0gYygtMC4wNSwgMS4wNSkpICsKICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkKCnAyIDwtIHAxICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyBJbnRybwoKVGhlc2UgYXJlIHNvbWUgcHJlbGltaW5hcnkgdmlzdWFsaXphdGlvbnMgb2YgdGhlIGRhdGEuCgpgYGB7ciBsb2FkaW5nIGRhdGEsIG1lc3NhZ2U9RkFMU0V9CnBoeWxvIDwtIHJlYWRfY3N2KCIuLi9kYXRhL3NwZWNpZXNfZGF0YS5jc3YiKSAlPiUgCiAgc2VsZWN0KHNwZWNpZXMsIHNwZWNpZXNfZm9ybWF0dGVkLCBjbGFkZSwgY2xhZGVfZm9ybWF0dGVkLCBwaHlsbykKCm1wX2RhdGEgPC0gcmVhZC5jc3YoIi4uL2RhdGEvbWVyZ2VkX2RhdGEvMDFfbWFueXByaW1hdGVzX3BpbG90X21lcmdlZF9kYXRhX3YyLmNzdiIsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpICU+JQogIGxlZnRfam9pbihwaHlsbywgYnkgPSAic3BlY2llcyIpICU+JQogIG11dGF0ZShzcGVjaWVzID0gc3BlY2llc19mb3JtYXR0ZWQsCiAgICAgICAgIHNwZWNpZXMgPSByZW9yZGVyKHNwZWNpZXMsIHBoeWxvKSwKICAgICAgICAgY2xhZGUgPSBjbGFkZV9mb3JtYXR0ZWQsCiAgICAgICAgIGNsYWRlID0gZmN0X3JlbGV2ZWwoY2xhZGUsICJMZW11ciIsICJOZXcgV29ybGQgbW9ua2V5IiwgIk9sZCBXb3JsZCBtb25rZXkiLCAiQXBlIiksCiAgICAgICAgIGRlbGF5ID0gZmFjdG9yKGRlbGF5KSkKYGBgCgojIE92ZXJ2aWV3IGJ5IHNwZWNpZXMKCkZpcnN0IGFuIG92ZXJ2aWV3IG9mIHRoZSBkYXRhLCBwbG90dGVkIGJ5IHNwZWNpZXMgYW5kIGRlbGF5LiBTbWFsbCwgdHJhbnNwYXJlbnQgZG90cyByZXByZXNlbnQgYWdncmVnYXRlZCBkYXRhIGZvciBlYWNoIGluZGl2aWR1YWwgYnkgZGVsYXkuIE9wZW4gZG90cyBhcmUgdGhlIGdyb3VwIG1lYW4gZm9yIHRoYXQgZGVsYXkuIEVycm9yIGJhcnMgYXJlIDk1JSBjb25maWRlbmNlIGludGVydmFscy4gVGV4dCBsYWJlbHMgYXJlIHRoZSBzYW1wbGUgc2l6ZS4KCmBgYHtyIG92ZXJ2aWV3IGJ5IHNwZWNpZXMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBsb3RfaW5kaXZpZHVhbCA8LSBtcF9kYXRhICU+JQogIGdyb3VwX2J5KHBoeWxvLCBjbGFkZSwgc3BlY2llcywgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpLAogICAgICAgICAgICBucl90cmlhbHMgPSBtYXgodHJpYWwpKQoKcGxvdF9ncm91cCA8LSBwbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyfQojIGdldCBzYW1wbGUgc2l6ZXMgKGZvciB1c2UgaW4gcGxvdHMpCm5zIDwtIG1wX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY2xhZGUsIHNwZWNpZXMpICU+JQogIG11dGF0ZShuID0gbl9kaXN0aW5jdChzdWJqZWN0X3NpdGUpKSAlPiUKICBncm91cF9ieShjbGFkZSwgc3BlY2llcywgc2l0ZSwgbikgJT4lCiAgc3VtbWFyaXNlKG5fYnlfc2l0ZSA9IG5fZGlzdGluY3Qoc3ViamVjdF9zaXRlKSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9NC41fQpwMiArIGFlcyh4ID0gZGVsYXksIHkgPSBjb3JyZWN0LCBjb2wgPSBkZWxheSkgKwogIGdlb21faml0dGVyKGRhdGEgPSBwbG90X2luZGl2aWR1YWwsIGFlcyhzaXplID0gbnJfdHJpYWxzKSwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMTUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4pLCBzaGFwZSA9IDEsIHNpemUgPSAzLCBzdHJva2UgPSAxLjUpICsKICBnZW9tX2xpbmVyYW5nZShkYXRhID0gcGxvdF9ncm91cCwgYWVzKHkgPSBOVUxMLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciksIGx3ZCA9IDEuMikgKwogICMgZ2VvbV90ZXh0KGRhdGEgPSBucywgYWVzKGxhYmVsID0gbiksIHkgPSAtLjA1LCB4ID0gMiwgY29sID0gImJsYWNrIiwgc2l6ZSA9IDMpICsKICBmYWNldF9ncmlkKHNwZWNpZXMgfiAuLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODAsIGhqdXN0ID0gMCkpICsKICBzY2FsZV9zaXplX2FyZWEoIk51bWJlciBvZiBUcmlhbHMiLCBtYXhfc2l6ZSA9IDMsIGJyZWFrcyA9IGMoMTIsIDI0LCAzNikpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCJEZWxheSIsIGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBjb29yZF9mbGlwKHlsaW0gPSAwOjEpCmBgYAoKYGBge3J9Cmdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzAxX292ZXJ2aWV3LnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNC41LCBzY2FsZSA9IDIpCmdnc2F2ZSgiLi4vZ3JhcGhzL0ZpZzIudGlmZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNC41LCBzY2FsZSA9IDIsIHR5cGUgPSAiY2Fpcm8iLCBjb21wcmVzc2lvbiA9ICJsenciKQpgYGAKCiMgT3ZlcnZpZXcgYnkgc3BlY2llcyBhY3Jvc3MgZGVsYXlzCgpgYGB7ciBvdmVydmlldyBieSBzcGVjaWVzIGFjcm9zcyBkZWxheXMsIHdhcm5pbmc9RkFMU0V9CnBsb3RfaW5kaXZpZHVhbDIgPC0gcGxvdF9pbmRpdmlkdWFsICU+JQogIGdyb3VwX2J5KGNsYWRlLCBzcGVjaWVzLCBzdWJqZWN0X3NpdGUpICU+JQogIHN1bW1hcmlzZShjb3JyZWN0ID0gbWVhbihjb3JyZWN0KSkKCnBsb3RfZ3JvdXAyIDwtIHBsb3RfaW5kaXZpZHVhbDIgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0xLjh9CnAxICsgYWVzKHggPSBmY3RfcmV2KHNwZWNpZXMpLCB5ID0gY29ycmVjdCwgY29sID0gY2xhZGUpICsKICBnZW9tX2ppdHRlcihkYXRhID0gcGxvdF9pbmRpdmlkdWFsMiwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMTUsIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcGxvdF9ncm91cDIsIGFlcyh5ID0gbWVhbiksIHNoYXBlID0gMSwgc2l6ZSA9IDMsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fbGluZXJhbmdlKGRhdGEgPSBwbG90X2dyb3VwMiwgYWVzKHkgPSBOVUxMLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciksIGx3ZCA9IDEuMikgKwogIGdlb21fdGV4dChkYXRhID0gbnMsIGFlcyhsYWJlbCA9IG4pLCB5ID0gLS4wNSwgY29sID0gImJsYWNrIiwgc2l6ZSA9IDMpICsKICBmYWNldF9ncmlkKGNsYWRlIH4gLiwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWVfeSIpICsKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wMl9vdmVydmlld19hY3Jvc3NfZGVsYXlzLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS44LCBzY2FsZSA9IDIpCmBgYAoKIyBQbG90cyBieSBzaXRlCgpIZXJlIHdlIHNlbGVjdCB0aGUgc3BlY2llcyBmb3Igd2hpY2ggd2UgaGF2ZSBkYXRhIGZyb20gbXVsdGlwbGUgc2l0ZXMuIFRoaXMgaXMgYSB2ZXJ5IHByZWxpbWluYXJ5IHdheSBvZiBjaGVja2luZyB3aGV0aGVyIHRoZXJlIGlzIGEgbG90IG9mIHZhcmlhdGlvbiBiZXR3ZWVuIHNpdGVzLiBQbG90dGluZyBjb252ZW50aW9ucyBhcmUgdGhlIHNhbWUgYXMgYWJvdmUuCgpGaXJzdCB3ZSBjaGVjayBmb3Igd2hpY2ggc3BlY2llcyB3ZSBoYXZlIGRhdGEgZnJvbSBtb3JlIHRoYW4gb25lIHNpdGU6CgpgYGB7ciBwbG90cyBieSBzaXRlLCByZXN1bHRzPSJhc2lzIn0KbXBfZGF0YSAlPiUKICBncm91cF9ieShzcGVjaWVzKSAlPiUKICBzdW1tYXJpc2Uoc2l0ZXMgPSBuX2Rpc3RpbmN0KHNpdGUpKSAlPiUKICBhcnJhbmdlKGRlc2Moc2l0ZXMpKSAlPiUKICBrbml0cjo6a2FibGUoKQpgYGAKCiMjIENoaW1wYW56ZWVzCgpgYGB7cn0KY2hpbXBfcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkNoaW1wYW56ZWUiKSAlPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpjaGltcF9wbG90X2dyb3VwIDwtIGNoaW1wX3Bsb3RfaW5kaXZpZHVhbCAlPiUKICAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTIuNX0KcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCwgY29sID0gZGVsYXkpICsKICBnZW9tX2ppdHRlcihkYXRhID0gY2hpbXBfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gY2hpbXBfcGxvdF9ncm91cCwgYWVzKHkgPSBtZWFuLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciksIHNpemUgPSAuOCwgc2hhcGUgPSAxLCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihucywgc3BlY2llcyA9PSAiQ2hpbXBhbnplZSIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZChzaXRlIH4gLiwgc3dpdGNoID0gInkiKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTgwKSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoYnJlYWtzID0gYygic2hvcnQiLCAibWVkaXVtIiwgImxvbmciKSkgKwogIGdndGl0bGUoIkNoaW1wYW56ZWVzIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQojIGdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzAzX2NoaW1wX2J5X3NpdGUucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLjUsIHNjYWxlID0gMiwgdHlwZSA9ICJjYWlybyIsIGNvbXByZXNzaW9uID0gImx6dyIpCmdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzAzX2NoaW1wX2J5X3NpdGUucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLjUsIHNjYWxlID0gMikKYGBgCgoKIyMgUmluZy10YWlsZWQgbGVtdXJzCgpgYGB7cn0KcnRsZW11cl9wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiUmluZy10YWlsZWQgbGVtdXIiKSAlPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpydGxlbXVyX3Bsb3RfZ3JvdXAgPC0gcnRsZW11cl9wbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0xLjJ9CnAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QsIGNvbCA9IGRlbGF5KSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IHJ0bGVtdXJfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gcnRsZW11cl9wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgc2l6ZSA9IC44LCBzaGFwZSA9IDEsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKG5zLCBzcGVjaWVzID09ICJSaW5nLXRhaWxlZCBsZW11ciIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZChzaXRlIH4gLiwgc3dpdGNoID0gInkiKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTgwKSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoYnJlYWtzID0gYygic2hvcnQiLCAibWVkaXVtIiwgImxvbmciKSkgKwogIGdndGl0bGUoIlJpbmctdGFpbGVkIGxlbXVycyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMDRfcnRsZW11cl9ieV9zaXRlLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKCiMjIEJyb3duIENhcHVjaGlucwoKYGBge3J9CmNhcF9wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQnJvd24gY2FwdWNoaW4gbW9ua2V5IikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQoKY2FwX3Bsb3RfZ3JvdXAgPC0gY2FwX3Bsb3RfaW5kaXZpZHVhbCAlPiUKICAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEuMn0KcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCwgY29sID0gZGVsYXkpICsKICBnZW9tX2ppdHRlcihkYXRhID0gY2FwX3Bsb3RfaW5kaXZpZHVhbCwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMywgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50cmFuZ2UoZGF0YSA9IGNhcF9wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgc2l6ZSA9IC44LCBzaGFwZSA9IDEsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKG5zLCBzcGVjaWVzID09ICJCcm93biBjYXB1Y2hpbiBtb25rZXkiKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICJ5IikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBnZ3RpdGxlKCJDYXB1Y2hpbiBNb25rZXlzIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wNV9jYXB1Y2hpbl9ieV9zaXRlLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKIyMgQm9ub2JvcwoKYGBge3J9CmJvbl9wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQm9ub2JvIikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQoKYm9uX3Bsb3RfZ3JvdXAgPC0gYm9uX3Bsb3RfaW5kaXZpZHVhbCAlPiUKICAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEuMn0KcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCwgY29sID0gZGVsYXkpICsKICBnZW9tX2ppdHRlcihkYXRhID0gYm9uX3Bsb3RfaW5kaXZpZHVhbCwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMywgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50cmFuZ2UoZGF0YSA9IGJvbl9wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgc2l6ZSA9IC44LCBzaGFwZSA9IDEsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKG5zLCBzcGVjaWVzID09ICJCb25vYm8iKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICJ5IikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBnZ3RpdGxlKCJCb25vYm9zIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wNl9ib25vYm9fYnlfc2l0ZS5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDEuMiwgc2NhbGUgPSAyKQpgYGAKCiMjIEdvcmlsbGEKCmBgYHtyfQpnb3JfcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkdvcmlsbGEiKSAlPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpnb3JfcGxvdF9ncm91cCA8LSBnb3JfcGxvdF9pbmRpdmlkdWFsICU+JQogICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwMiArIGFlcyh4ID0gZGVsYXksIHkgPSBjb3JyZWN0LCBjb2wgPSBkZWxheSkgKwogIGdlb21faml0dGVyKGRhdGEgPSBnb3JfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gZ29yX3Bsb3RfZ3JvdXAsIGFlcyh5ID0gbWVhbiwgeW1pbiA9IGNpX2xvd2VyLCB5bWF4ID0gY2lfdXBwZXIpLCBzaXplID0gLjgsIHNoYXBlID0gMSwgc3Ryb2tlID0gMS41KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIobnMsIHNwZWNpZXMgPT0gIkdvcmlsbGEiKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICJ5IikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBnZ3RpdGxlKCJHb3JpbGxhcyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMDdfZ29yaWxsYV9ieV9zaXRlLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKIyBUYXNrLWV4cGVyaWVuY2UKCkhlcmUgd2Ugc3BsaXQgZWFjaCBzcGVjaWVzIGJ5IHRhc2sgZXhwZXJpZW5jZS4gQ2hlY2sgaWYgd2UgaGF2ZSBzcGVjaWVzIHdpdGggc3VmZmljaWVudCBtZW1lYmVycyBoYXZpbmcgZGlmZmVyZW50IGxldmVscyBvZiB0YXNrIGV4cGVyaWVuY2UuCgpgYGB7ciBwbG90cyBieSB0YXNrIGV4cGVyaWVuY2UsIHJlc3VsdHM9ImFzaXMifQptcF9kYXRhICU+JQogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQogIG11dGF0ZShsdmxzX3Rhc2tfZXhwID0gbl9kaXN0aW5jdCh0YXNrX2V4cGVyaWVuY2UpKSAlPiUKICBmaWx0ZXIobHZsc190YXNrX2V4cCA+IDEpICU+JQogIGdyb3VwX2J5KHNwZWNpZXMsIHRhc2tfZXhwZXJpZW5jZSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuX2Rpc3RpbmN0KHN1YmplY3Rfc2l0ZSkpICU+JQogIGtuaXRyOjprYWJsZSgpCmBgYAoKYGBge3J9CiMgZ2V0IHNhbXBsZSBzaXplcyAoZm9yIHVzZSBpbiBwbG90cykKbnNfdGFza19leHAgPC0gbXBfZGF0YSAlPiUKICBncm91cF9ieShjbGFkZSwgc3BlY2llcykgJT4lCiAgbXV0YXRlKG4gPSBuX2Rpc3RpbmN0KHRhc2tfZXhwZXJpZW5jZSkpICU+JQogIGdyb3VwX2J5KGNsYWRlLCBzcGVjaWVzLCB0YXNrX2V4cGVyaWVuY2UsIG4pICU+JQogIHN1bW1hcmlzZShuX2J5X3NpdGUgPSBuX2Rpc3RpbmN0KHN1YmplY3Rfc2l0ZSkpCmBgYAoKU28gZmFyLCB0aGlzIG9ubHkgYXBwbGllcyB0byBjaGltcHMgYW5kIGJvbm9ib3MuIEhvd2V2ZXIsIHRhc2sgZXhwZXJpZW5jZSBjby12YXJpZXMgd2l0aCBzaXRlLgoKPCEtLSAjIyBDaGltcGFuemVlcyAtLT4KCmBgYHtyfQpjaGltcF90YXNrX3Bsb3RfaW5kaXZpZHVhbCA8LSBtcF9kYXRhICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJDaGltcGFuemVlIikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgdGFza19leHBlcmllbmNlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpjaGltcF90YXNrX3Bsb3RfZ3JvdXAgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQ2hpbXBhbnplZSIpICU+JQogIGdyb3VwX2J5KHRhc2tfZXhwZXJpZW5jZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKSAlPiUKICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwX3Rhc2tleHBfY2hpbXAgPC0gcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCkgKwogIGdlb21faml0dGVyKGRhdGEgPSBjaGltcF90YXNrX3Bsb3RfaW5kaXZpZHVhbCwgYWVzKGNvbCA9IHNpdGUpLCB3aWR0aCA9IC4zLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC41LCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gY2hpbXBfdGFza19wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyLCBzaGFwZSA9IGRlbGF5KSwgc2l6ZSA9IC44LCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihuc190YXNrX2V4cCwgc3BlY2llcyA9PSAiQ2hpbXBhbnplZSIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZCh0YXNrX2V4cGVyaWVuY2UgfiAuLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZShsZWdlbmQuYm94ID0gImhvcml6b250YWwiLCBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODApKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMSwgMiwgNSksIGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCkgKwogIGdndGl0bGUoIkNoaW1wYW56ZWVzIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCjwhLS0gIyMgQm9ub2JvcyAtLT4KCmBgYHtyfQpib25vYm9fdGFza19wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQm9ub2JvIikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgdGFza19leHBlcmllbmNlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpib25vYm9fdGFza19wbG90X2dyb3VwIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkJvbm9ibyIpICU+JQogIGdyb3VwX2J5KHRhc2tfZXhwZXJpZW5jZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKSAlPiUKICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwX3Rhc2tleHBfYm9uIDwtIHAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QpICsKICBnZW9tX2ppdHRlcihkYXRhID0gYm9ub2JvX3Rhc2tfcGxvdF9pbmRpdmlkdWFsLCBhZXMoY29sID0gc2l0ZSksIHdpZHRoID0gLjMsIGhlaWdodCA9IC4wMTUsIGFscGhhID0gLjUsIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludHJhbmdlKGRhdGEgPSBib25vYm9fdGFza19wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyLCBzaGFwZSA9IGRlbGF5KSwgc2l6ZSA9IC44LCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihuc190YXNrX2V4cCwgc3BlY2llcyA9PSAiQmJvbm9ibyIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZCh0YXNrX2V4cGVyaWVuY2UgfiAuLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZShsZWdlbmQuYm94ID0gImhvcml6b250YWwiLCBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODApKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMSwgMiwgNSksIGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCkgKwogIGdndGl0bGUoIkJvbm9ib3MiKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTN9CmdyaWQuYXJyYW5nZShwX3Rhc2tleHBfY2hpbXAsIHBfdGFza2V4cF9ib24sIG5jb2wgPSAxKQpgYGAKCmBgYHtyfQpncm9iIDwtIGFycmFuZ2VHcm9iKHBfdGFza2V4cF9jaGltcCwgcF90YXNrZXhwX2JvbiwgbmNvbCA9IDEpCmdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzA4X3Rhc2tfZXhwZXJpZW5jZS5wbmciLCBncm9iLCB3aWR0aCA9IDQsIGhlaWdodCA9IDMsIHNjYWxlID0gMikKYGBgCgoKIyBBZ2UKCkhlcmUgd2UgcGxvdCBhZ2UgYWdhaW5zdCBjb3JyZWN0IGNob2ljZSBzZXBhcmF0ZSBmb3IgZWFjaCBkZWxheSBhbmQgc3BlY2llcy4gUmVncmVzc2lvbiBsaW5lIGlzIHNtb290aGVkIGRlbGF5YWwgbWVhbi4KCmBgYHtyfQpwbG90X2FnZSA8LSBtcF9kYXRhICU+JQogIG11dGF0ZShkZWxheSA9IGZjdF9yZXYoZGVsYXkpKSAlPiUKICBncm91cF9ieShzdWJqZWN0X3NpdGUsIG5vcm1fYWdlLCBjbGFkZSwgc3BlY2llcywgZGVsYXkpICU+JQogIHN1bW1hcmlzZShjb3JyZWN0ID0gbWVhbihjb3JyZWN0KSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4zfQpnZ3Bsb3QocGxvdF9hZ2UsIGFlcyh4ID0gbm9ybV9hZ2UsIHkgPSBjb3JyZWN0KSkgKwogIGdlb21faml0dGVyKGFlcyhjb2wgPSBjbGFkZSksIHdpZHRoID0gLjA1LCBoZWlnaHQgPSAuMDUsIGFscGhhID0gLjUsIHNpemUgPSAyLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAiYmxhY2siKSArCiAgIyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsdHkgPSAyKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMS8zLCBsdHkgPSAyKSArCiAgZmFjZXRfZ3JpZCh+IGRlbGF5KSArCiAgbGFicyh4ID0gIk5vcm1lZCBBZ2UgKHJlbGF0aXZlIHRvIHNwZWNpZXMgbG9uZ2V2aXR5KSIsIHkgPSAiUHJvcG9ydGlvbiBDb3JyZWN0IikgKwogIHNjYWxlX2NvbG9yX3NvbGFyaXplZCgiQ2xhZGUiKSArCiAgeWxpbShjKC0uMDUsIDEuMDUpKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wOV9hZ2VfYnlfZGVsYXkucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAxLjMsIHNjYWxlID0gMikKZ2dzYXZlKCIuLi9ncmFwaHMvRmlnNC50aWZmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAxLjMsIHNjYWxlID0gMiwgdHlwZSA9ICJjYWlybyIsIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTMuNH0KZ2dwbG90KHBsb3RfYWdlLCBhZXMoeCA9IG5vcm1fYWdlLCB5ID0gY29ycmVjdCkpICsKICBnZW9tX2ppdHRlcihhZXMoZmlsbCA9IHNwZWNpZXMpLCB3aWR0aCA9IC4wNSwgaGVpZ2h0ID0gLjA1LCBhbHBoYSA9IC41LCBzaXplID0gMi41LCBzaGFwZSA9IDIxLCBzdHJva2UgPSAwKSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbCA9IGRlbGF5KSwgbWV0aG9kID0gImxtIiwgc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5ID0gMikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEvMywgbHR5ID0gMikgKwogIGZhY2V0X2dyaWQoZGVsYXkgfiBjbGFkZSwgc2NhbGVzID0gImZyZWVfeCIpICsKICBsYWJzKHggPSAiTm9ybWVkIEFnZSAocmVsYXRpdmUgdG8gc3BlY2llcyBsb25nZXZpdHkpIiwgeSA9ICJQcm9wb3J0aW9uIENvcnJlY3QiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KHNvbGFyaXplZF9wYWxldHRlKDMpKSkgKwogIHlsaW0oYygtLjA1LCAxLjA1KSkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMTBfYWdlX2J5X2RlbGF5X3NwZWNpZXMucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLjQsIHNjYWxlID0gMikKYGBgCgoKIyBDdXAgZGlzdGFuY2UKCihzaWcuIGVmZmVjdCBpbiBwcmVsaW1pbmFyeSBtb2RlbCkKCmBgYHtyfQpwbG90X2N1cCA8LSBtcF9kYXRhICU+JQogICBncm91cF9ieShzdWJqZWN0X3NpdGUsIGN1cF9kaXN0YW5jZSwgY2xhZGUsIHNwZWNpZXMsIGRlbGF5KSAlPiUKICAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQpgYGAKCmBgYHtyIHBsb3R0aW5nIGN1cCBkaXN0YW5jZSwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9Mn0KY3AgPC0gZ2dwbG90KHBsb3RfY3VwLCBhZXMoeCA9IGN1cF9kaXN0YW5jZSwgeSA9IGNvcnJlY3QpKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbCA9IGNsYWRlKSwgd2lkdGggPSAuNSwgaGVpZ2h0ID0gLjE1LCBhbHBoYSA9IC41LCBzaXplID0gMikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJibGFjayIpICsKICBsYWJzKHggPSAiQ3VwIERpc3RhbmNlIGluIGNtIiwgeSA9ICJQcm9wb3J0aW9uIENvcnJlY3QiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMS8zLCBsdHkgPSAyKSArCiAgc2NhbGVfY29sb3Jfc29sYXJpemVkKCJDbGFkZSIpICsKICB5bGltKGMoLS4wNSwgMS4wNSkpCgpjcCArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKC41LCA1LCAuNSwgLjUpLCAiY20iKSkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMTFfY3VwX2Rpc3RhbmNlLnBuZyIsIGNwLCB3aWR0aCA9IDMsIGhlaWdodCA9IDIsIHNjYWxlID0gMikKYGBgCgo=